﻿using NetBase.ColorMath;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Color = System.Windows.Media.Color;
using Net.ColorMath;
using Net.NetBase;
using System.Diagnostics;

namespace NetBase
{
    public class SqRt
    {
        public SqRt(int x, int y, SqImgLayer layer)
        {
            this.x = x;
            this.y = y;
            this.layer = layer;
            nels = new Dictionary<XY, SqRt>();
        }
        private int x;
        private int y;
        private SqImgLayer layer;
        private Color inputColor;
        /// <summary>
        /// Neighbours elements = nels
        /// </summary>
        public Dictionary<XY, SqRt> nels;

        public int X { get { return x; } }
        public int Y { get { return y; } }
        public SqImgLayer Layer { get { return layer; } }
        public System.Windows.Media.Color Input { get { return inputColor; } }

        // Neighbour gain #1
        public double NeighbourColorGain { get; set; }
        public double NeighbourColorGain2 { get; set; }

        // Neighbour gain #2
        public double NCG1 { get; set; }
        public double NCG2 { get; set; }
        public bool IsNCG { get; set; }
        public bool IsNCGMax { get; set; }
        internal SqRt NCGOwner { get; set; }

        // Investigation clusterization
        public double S1 { get; set; }
        public double S2 { get; set; }

        // Stage1
        private SqRt nearestByColor;
        public SqRtGroup ColorGroup = null;

        public SqRt NearestByColor
        {
            get
            {
                return nearestByColor;
            }
        }


        public void setInput(System.Drawing.Color color)
        {
            inputColor = System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B);
        }

        internal void InitializeLayerRelations()
        {
            if (Y > 0) nels.Add(XY.XYUp, layer[X, Y - 1]);
            if (Y < (layer.Height - 1)) nels.Add(XY.XYDown, layer[X, Y + 1]);
            if (X < (layer.Width - 1)) nels.Add(XY.XYRight, layer[X + 1, Y]);
            if (X > 0) nels.Add(XY.XYLeft, layer[X - 1, Y]);
        }

        public SqRt GetNearest()
        {
            nearestByColor = nels.Values.ArgMin(el => CW.GetModule(el.inputColor - inputColor));
            //if ((this.ColorGroup == null) && (nearestByColor.ColorGroup == null))
            //{
            //    int newIndex = this.Layer.SqRtGroups.Keys.Union(new int[] {0}).Max() + 1;
            //    var newColorGroup = new SqRtGroup() { GroupId = newIndex };
            //    this.Layer.SqRtGroups.Add(newIndex, newColorGroup);
            //    ColorGroup = newColorGroup;
            //    nearestByColor.ColorGroup = newColorGroup;
            //}
            //else if ((this.ColorGroup == null) && ( nearestByColor.ColorGroup != null))
            //{
            //    this.ColorGroup = nearestByColor.ColorGroup;
            //}
            //else if ((this.ColorGroup != null) && (nearestByColor.ColorGroup == null))
            //{
            //    nearestByColor.ColorGroup = this.ColorGroup;
            //}
            return nearestByColor;
        }

        public void NeighbourGain()
        {
            double ncg = 1;
            foreach ( var el in nels )
            {

                var colDif = CW.GetModule( el.Value.inputColor - inputColor );
                double Nx = NeuroMath.LimitedImpedance(colDif);
                ncg *= Nx;
            }
            NeighbourColorGain = ncg;
            Trace.TraceInformation(String.Format("ncg = {0}", ncg));
            S1 = ncg;
        }



        internal void NeighbourGain2()
        {
            double vv = NeighbourColorGain;
            foreach (var el in nels)
            {
                vv *= el.Value.NeighbourColorGain;
            }
            NeighbourColorGain2 = vv;
        }

        internal void NegativeFeedbackColorGain()
        {
            double ncg = 10;
            foreach (var el in nels)
            {

                var colDif = CW.GetModule(el.Value.inputColor - inputColor);
                double Nx = NeuroMath.LimitedImpedance(colDif);
                ncg *= Nx;
            }
            Trace.TraceInformation(String.Format( "S1 = {0}", S1  ));
            ncg = NeuroMath.GainBackFront(S1) * ncg;

            S2 = NeuroMath.GainTo1(ncg);
        }


        internal void NeighbourGainEasy1()
        {
            double imp = 0;
            foreach (var el in nels)
            {
                var colDif = CW.GetModule(el.Value.inputColor - inputColor);
                //double Nx = NeuroMath.LimitedImpedance(colDif);
                imp += colDif;
            }
            this.NCG1 = imp / 4;
        }

        internal void NeighbourGainEasy2()
        {
            ElementRingOverLayerIterator iterator = new ElementRingOverLayerIterator(layer, x, y, 1);
            double imp = 0;
            int count = 0;
            foreach ( var el in iterator)
            {
                imp += el.NCG1;
                if (count == 0)
                {
                    imp += 2 * el.NCG1;
                    count += 2;
                }
                count++;

            }
            //foreach ( var el in nels )
            //{
                //var colDif = CW.GetModule(el.Value.inputColor - inputColor);
                //imp += el.Value.NCG1;
            //}
            NCG2 = imp / count;
        }

        public Area Area { get; set; }

        public bool IsAreaBorder { get; set; }
    }
}
